package com.education.platform.api.pay.wxpay;

import com.alibaba.fastjson.JSON;
import com.education.platform.api.service.PayRecordService;
import com.education.platform.api.vo.request.PayRecordUpdateVO;
import com.education.platform.common.util.StringUtils;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
 * 微信支付服务
 */
@Service
public class WxServiceImpl implements WxService {
    private static final Logger logger = LoggerFactory.getLogger(WxServiceImpl.class);

    @Autowired
    private PayRecordService payRecordService;

    /**
     * 统一下单， 成功后，返回app参数调起微信app
     * 官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
     * @param
     * @param
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, String> wxPay(PayRecordUpdateVO payRequestVO)throws Exception  {
        //请求预支付订单
        Map<String, String> result;
        result  = this.unifiedOrder(payRequestVO);
        Map<String, String> map = new HashMap<>(8);
        //参加调起支付的签名字段有且只能是6个，
        // 分别为appid、partnerid、prepayid、package、noncestr和timestamp，
        // 而且都必须是小写
        map.put("appid", result.get("appid"));
        map.put("partnerid", result.get("mch_id"));
        map.put("prepayid", result.get("prepay_id"));
        map.put("package", "Sign=WXPay");
        map.put("noncestr", result.get("nonce_str"));
        //单位为秒
        map.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        //  这里不要使用请求预支付订单时返回的签名
        map.put("sign",WXPayUtil.generateSignature(map, WxPayConfig.KEY, WXPayConstants.SignType.MD5));
        return map;
    }


    /**
     * 调用官方SDK 获取预支付订单等参数
     * @param
     * @param
     * @return
     * @throws
     */

    private Map<String, String> unifiedOrder(PayRecordUpdateVO payRequestVO) throws Exception {
        Map<String, String> returnMap = new HashMap<>();
        WxPayConfig config = new WxPayConfig();
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>(10);
        //生成商户订单号，不可重复
        data.put("appid", config.getAppID());
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("body", StringUtils.isEmpty(payRequestVO.getSubject())?"订单支付":payRequestVO.getSubject());
        data.put("out_trade_no", payRequestVO.getOrderNo());
        //金额 单位 分
        data.put("total_fee", payRequestVO.getTotalPrice().multiply(new BigDecimal("100")).setScale(0).toPlainString());

        //自己的服务器IP地址
        data.put("spbill_create_ip", WxPayConfig.SPBILL_CREATE_IP);
        //异步通知地址（请注意必须是外网）
        data.put("notify_url", WxPayConfig.NOTIFY_URL);
        //交易类型
        data.put("trade_type", WxPayConfig.TRADE_TYPE_APP);
        //附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据 不是必填
          data.put("attach", "支付测试");
        String sign =WXPayUtil.generateSignature(data, WxPayConfig.KEY);
        data.put("sign", sign);

            //使用官方API请求预付订单
            Map<String, String> response = wxpay.unifiedOrder(data);
            System.out.println(response);
            //获取返回码
            String returnCode = response.get("return_code");
            //若返回码为SUCCESS，则会返回一个result_code,再对该result_code进行判断
            //主要返回以下5个参数
            if (returnCode.equals(WXPayConstants.SUCCESS)) {
                String resultCode = response.get("result_code");
                returnMap.put("appid", response.get("appid"));
                returnMap.put("mch_id", response.get("mch_id"));
                returnMap.put("nonce_str", response.get("nonce_str"));
                returnMap.put("sign", response.get("sign"));
                //resultCode 为SUCCESS，才会返回prepay_id和trade_type
                if (WXPayConstants.SUCCESS.equals(resultCode)) {
                    //获取预支付交易回话标志
                    returnMap.put("trade_type", response.get("trade_type"));
                    returnMap.put("prepay_id", response.get("prepay_id"));
                    return returnMap;
                } else {
                    //此时返回没有预付订单的数据
                    return returnMap;
                }
            } else {
                return returnMap;
            }

    }

    /**
     *
     * @param notifyData 异步通知后的XML数据
     * @return
     */
    @Override
    public  Map<String,String> payBack(String notifyData) {
        logger.info("微信回调通知的xml："+notifyData);
        Map<String,String> resultMap = new HashMap<>(2);
        WxPayConfig config = null;
        try {
            config = new WxPayConfig();
        } catch (Exception e) {
            e.printStackTrace();
        }
        WXPay wxpay = new WXPay(config);
        Map<String, String> notifyMap = null;
        try {
            // 调用官方SDK转换成map类型数据
            notifyMap = WXPayUtil.xmlToMap(notifyData);
            logger.info("微信回调通知的xml转map："+ JSON.toJSONString(notifyMap));
            //验证签名是否有效，有效则进一步处理
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                logger.info("微信手机支付回调通知验证签名 正确！："+ JSON.toJSONString(notifyMap));
                //状态
                String return_code = notifyMap.get("return_code");
                //商户订单号
                String out_trade_no = notifyMap.get("out_trade_no");
                //微信交易id
                String transaction_id = notifyMap.get("transaction_id");
                logger.info("return_code=",return_code);
                logger.info("out_trade_no=",out_trade_no);
                logger.info("transaction_id=",transaction_id);
                if (return_code.equals(WXPayConstants.SUCCESS)) {
                    if (out_trade_no != null) {
                       logger.info("支付成功");
                        resultMap.put("return_code", WXPayConstants.SUCCESS);
                        resultMap.put("return_msg","OK");
                        payRecordService.paySuccess(out_trade_no,transaction_id);
                    } else {
                        resultMap.put("return_code", WXPayConstants.FAIL);
                        resultMap.put("return_msg","报文为空");
                    }
                }else{
                    resultMap.put("return_code", WXPayConstants.FAIL);
                    resultMap.put("return_msg","失败");
                }
            } else {
                // 签名错误，如果数据里没有sign字段，也认为是签名错误
                logger.error("微信手机支付回调通知签名验证错误");
                resultMap.put("return_code", WXPayConstants.FAIL);
                resultMap.put("return_msg","报文为空");
            }
        } catch (Exception e) {
            logger.error("手机支付回调通知失败", e);
            resultMap.put("return_code", WXPayConstants.FAIL);
            resultMap.put("return_msg","报文为空");
        }
        return resultMap;
    }
}
